package com.dome.gateway.rule;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.ribbon.ExtendBalancer;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.dome.auth.UserContextHolder;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: hz
 * @time: 2021/5/3 15:27
 */
@Slf4j
public class GrayNacosRule extends AbstractLoadBalancerRule {

    public static final String META_DATA_KEY_VERSION = "version";
    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    @Override
    public Server choose(Object key) {
        try {
            String clusterName = this.nacosDiscoveryProperties.getClusterName();
            DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
            String name = loadBalancer.getName();

            NamingService namingService = nacosDiscoveryProperties
                    .namingServiceInstance();
            List<Instance> instances = namingService.selectInstances(name, true);
            if (CollectionUtils.isEmpty(instances)) {
                log.warn("no instance in service {}", name);
                return null;
            }
            List<Instance> instancesToChoose = instances;
            if (StringUtils.isNotBlank(clusterName)) {
                List<Instance> sameClusterInstances = instances.stream()
                        .filter(instance -> Objects.equals(clusterName,
                                instance.getClusterName()))
                        .collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(sameClusterInstances)) {
                    instancesToChoose = sameClusterInstances;
                } else {
                    log.warn("发生跨集群的调用，name = {}, clusterName = {}, instance = {}", name, clusterName, instances);
                }
            }

            String hystrixVer = UserContextHolder.getInstance().getVersion();
            //String hystrixVer = "";
            //带版本的服务
            List<Instance> metaInstanceList = new ArrayList<>();
            //不带版本的服务
            List<Instance> originMetaInstanceList = new ArrayList<>();
            log.info("服务:{}:  hystrixVer:{}", name, hystrixVer);
            //如果头部有传输版本号.就走筛选的逻辑
            for (Instance instance : instancesToChoose) {

                Map<String, String> metadata = instance.getMetadata();

                // version策略 如果 eureka.instance.metadata-map有配值version
                String metaVersion = metadata.get(META_DATA_KEY_VERSION);
                if (StringUtils.isNotEmpty(metaVersion)) {
                    //如果version存在.且匹配上了.就存入带版本的集合
                    if (metaVersion.equals(hystrixVer)) {
                        metaInstanceList.add(instance);
                    }else{
                        originMetaInstanceList.add(instance);
                    }
                } else {
                    originMetaInstanceList.add(instance);
                }
            }
            if (!CollectionUtils.isEmpty(metaInstanceList)) {
                return originChoose(metaInstanceList);
            } else {
                return originChoose(originMetaInstanceList);
            }
        } catch (Exception e) {
            log.warn("GrayNacosRule error", e);
            return null;
        }
    }

    private Server originChoose(List<Instance> instancesToChoose) {

        Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToChoose);

        return new NacosServer(instance);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {
    }


   /* @Override
    public Server choose(Object key) {
        try {
            String clusterName = this.nacosDiscoveryProperties.getClusterName();
            DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
            String name = loadBalancer.getName();

            NamingService namingService = nacosDiscoveryProperties
                    .namingServiceInstance();
            List<Instance> instances = namingService.selectInstances(name, true);
            if (CollectionUtils.isEmpty(instances)) {
                log.warn("no instance in service {}", name);
                return null;
            }
            List<Instance> instancesToChoose = instances;
            if (StringUtils.isNotBlank(clusterName)) {
                List<Instance> sameClusterInstances = instances.stream()
                        .filter(instance -> Objects.equals(clusterName,
                                instance.getClusterName()))
                        .collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(sameClusterInstances)) {
                    instancesToChoose = sameClusterInstances;
                } else {
                    log.warn("发生跨集群的调用，name = {}, clusterName = {}, instance = {}", name, clusterName, instances);
                }
            }

            String hystrixVer = UserContextHolder.getInstance().getVersion();
            List<Instance> metaInstanceList = new ArrayList<>();
            List<Instance> originMetaInstanceList = new ArrayList<>();
            if (StringUtils.isNotEmpty(hystrixVer)) {
            log.info("服务:{}:  hystrixVer:{}", name, hystrixVer);
            //如果头部有传输版本号.就走筛选的逻辑
            for (Instance instance : instancesToChoose) {

                Map<String, String> metadata = instance.getMetadata();

                // version策略 如果 eureka.instance.metadata-map有配值version
                String metaVersion = metadata.get(META_DATA_KEY_VERSION);
                if (StringUtils.isNotEmpty(metaVersion)) {
                    //如果version存在.且匹配上了.就存入集合
                    if (metaVersion.equals(hystrixVer)) {
                        metaInstanceList.add(instance);
                    }
                } else {
                    originMetaInstanceList.add(instance);
                }
            }
            if (!CollectionUtils.isEmpty(metaInstanceList)) {
                return originChoose(metaInstanceList);
            }
            } else {
                //如果没有版本头.走原来nacos负载均衡逻辑
                return originChoose(originMetaInstanceList);
            }
        } catch (Exception e) {
            log.warn("GrayNacosRule error", e);
            return null;
        }
        return null;
    }*/

}